#include "ChannelManager.h"
#include "IChannel.h"
#include "Channel.h"
#include "Configuration.h"

IChannelManager*	ChannelManager::_instance = NULL;

ChannelManager::ChannelManager()
{
	this->LoadChannel();
}

IChannelManager*	ChannelManager::GetChannelManager(void)
{
	if (!ChannelManager::_instance)
		ChannelManager::_instance = new ChannelManager();
	return ChannelManager::_instance;
}

const unsigned int	ChannelManager::LoadChannel()
{
	//load from database
	IDatabase::DbResult* result = Configuration::GetConfiguration()->GetDatabase()->SelectAllChannel();
	for (unsigned int idx = 0; idx < result->size(); idx++)
	{
		IChannel *parentChannel = NULL;
		if ((*result->at(idx))["parentId"]->GetValueInt() != 0)
		{
			//new Channel((*result->at(idx))["id"]->GetValueInt(), (*result->at(idx))["name"]->GetValueString(), (*result->at(idx))["maxNameLenght"]->GetValueInt(), (*result->at(idx))["password"]->GetValueString(), (*result->at(idx))["maxPasswordLenght"]->GetValueInt(), (*result->at(idx))["motd"]->GetValueString(), (*result->at(idx))["maxMotdLenght"]->GetValueInt(), (*result->at(idx))["description"]->GetValueString(), (*result->at(idx))["maxDescriptionLenght"]->GetValueInt(), (*result->at(idx))["visibility"]->GetValueBool(), (*result->at(idx))["maxUser"]->GetValueInt(), (*result->at(idx))["maxTalker"]->GetValueInt());
			
			//this->_mainChannel.push_back(channel);
		/*}
		else
		{*/
			IChannel *parentChannel = this->GetChannel((*result->at(idx))["parentId"]->GetValueInt());
			//this->_channel.push_back();
		}
		IChannel*	channel = new Channel((*result->at(idx))["id"]->GetValueInt(), parentChannel, (*result->at(idx))["name"]->GetValueString(), (*result->at(idx))["maxNameLenght"]->GetValueInt(), (*result->at(idx))["password"]->GetValueString(), (*result->at(idx))["maxPasswordLenght"]->GetValueInt(), (*result->at(idx))["motd"]->GetValueString(), (*result->at(idx))["maxMotdLenght"]->GetValueInt(), (*result->at(idx))["description"]->GetValueString(), (*result->at(idx))["maxDescriptionLenght"]->GetValueInt(), (*result->at(idx))["visibility"]->GetValueBool(), (*result->at(idx))["maxUser"]->GetValueInt(), (*result->at(idx))["maxTalker"]->GetValueInt());
		this->_channel.push_back(channel);
	}
	return 0;
}

IChannel*	ChannelManager::CreateChannel(const std::string& name, const unsigned int maxNameLenght, const std::string& password, const unsigned int maxPasswordLenght, const std::string& motd, const unsigned int maxMotdLenght, const std::string& description, const unsigned int maxDescriptionLenght, const bool visible, const unsigned int maxUser, const unsigned int maxTalker)
{
	//creer dans la base le channel 'Root'
	Configuration::GetConfiguration()->GetDatabase()->CreateChannel(0, name, maxNameLenght, password, maxPasswordLenght, motd, maxMotdLenght, description, maxDescriptionLenght, visible, maxUser, maxTalker);
	IChannel*	channel = new Channel(0, NULL, name, maxNameLenght, password, maxPasswordLenght, motd, maxMotdLenght, description, maxDescriptionLenght, visible, maxUser, maxTalker);
	this->_channel.push_back(channel);
	return channel;
}

IChannel*	ChannelManager::CreateChannel(IChannel* parent, const std::string& name, const unsigned int maxNameLenght, const std::string& password, const unsigned int maxPasswordLenght, const std::string& motd, const unsigned int maxMotdLenght, const std::string& description, const unsigned int maxDescriptionLenght, const bool visible, const unsigned int maxUser, const unsigned int maxTalker)
{
	//creer dans la base
	unsigned int id = Configuration::GetConfiguration()->GetDatabase()->CreateChannel(parent->GetId(), name, maxNameLenght, password, maxPasswordLenght, motd, maxMotdLenght, description, maxDescriptionLenght, visible, maxUser, maxTalker);
	IChannel*	channel = new Channel(id, parent, name, maxNameLenght, password, maxPasswordLenght, motd, maxMotdLenght, description, maxDescriptionLenght, visible, maxUser, maxTalker);
	this->_channel.push_back(channel);
	return channel;
}

//const unsigned int	ChannelManager::DeleteChannel(IChannel* channel)
//{
//	if (!channel->HaveParent())
//		this->_mainChannel.remove(channel);
//	channel->DeleteChannel();
//	this->_channel.remove(channel);
//	//faire le delete channel ici ou pas ?
//	return 0;
//}

void				ChannelManager::DeleteChannel()
{
	//Configuration::GetConfiguration()->GetDatabase()->DeleteAllChannel();

	//std::list<IChannel*>::iterator	iteCurrent = this->_channel.begin();
	//std::list<IChannel*>::iterator	iteEnd = this->_channel.end();
	//while (iteCurrent != iteEnd)
	//{	
	//	(*iteCurrent)->DeleteChannel();
	//	delete (*iteCurrent);
	//	++iteCurrent;
	//}
	//this->_channel.clear();

	// plus propre et moins casse geule
	IChannel*	channelRoot = this->GetChannel(0);
	std::list<IChannel*>::iterator	iterCurrent = channelRoot->GetChannelChild()->begin();
	std::list<IChannel*>::iterator	iterEnd = channelRoot->GetChannelChild()->end();
	while (iterCurrent != iterEnd)
	{
		this->DeleteChannel((*iterCurrent));
		++iterCurrent;
	}
}

const unsigned int	ChannelManager::DeleteChannel(const unsigned int id)
{
	IChannel*	channel = this->GetChannel(id);
	this->DeleteChannel(channel);
	return 0;
}

const unsigned int	ChannelManager::DeleteChannel(IChannel*	channel)
{
	//suppression dans la base
	channel->DeleteChannel();
	//suppression du channel lie aux users dans la liste des users du channel
	std::list<IUser*>::iterator	iteCurrent = channel->GetUser()->begin();
	std::list<IUser*>::iterator	iteEnd = channel->GetUser()->end();
	while (iteCurrent != iteEnd)
	{
		//(*iteCurrent)->SetCurrentChannel(NULL); prob UML include IUser dans IChannel et inversement :/ visiblement fixed
		(*iteCurrent)->SetNoCurrentChannel(); //on reatribue plutot au channel root
		++iteCurrent;
	}
	//on applique le meme procede a tout les child du channel
	std::list<IChannel*>::iterator	iterCurrent = channel->GetChannelChild()->begin();
	std::list<IChannel*>::iterator	iterEnd = channel->GetChannelChild()->end();
	while (iterCurrent != iterEnd)
	{
		this->DeleteChannel((*iterCurrent));
		++iterCurrent;
	}
	//et on enleve ce channel de la list des channel de son parent
	if (channel->HaveParent())
		channel->GetParent()->RemoveChannelChild(channel);

	this->_channel.remove(channel);
	delete channel;
	return 0;
}

//const unsigned int	ChannelManager::DeleteChannel(const std::string& pattern)
//{
//	IChannel* channel = this->GetChannel(pattern);
//	this->DeleteChannel(channel);
//	return 0;
//}



// WARNING : fonction move qui se base sur le nom, on peut avoir deux channels du meme nom si ils sont dans
// deux channels parents differents ... donc peut etre a supprimer
const unsigned int	ChannelManager::MoveChannel(IChannel* channel, IChannel* parent)
{
	channel->SetParent(parent);
	return 0;
}

const unsigned int	ChannelManager::MoveChannel(IChannel* channel, const unsigned int idParent)
{
	channel->SetParent(this->GetChannel(idParent));
	return 0;
}

const unsigned int	ChannelManager::MoveChannel(IChannel* channel, const std::string& patternParent)
{
	channel->SetParent(this->GetChannel(patternParent));
	return 0;
}

const unsigned int	ChannelManager::MoveChannel(const unsigned int idChannel, IChannel* parent)
{
	this->GetChannel(idChannel)->SetParent(parent);
	return 0;
}

const unsigned int	ChannelManager::MoveChannel(const unsigned int idChannel, const unsigned int idParent)
{
	this->GetChannel(idChannel)->SetParent(this->GetChannel(idParent));
	return 0;
}

const unsigned int	ChannelManager::MoveChannel(const unsigned int idChannel, const std::string& patternParent)
{
	this->GetChannel(idChannel)->SetParent(this->GetChannel(patternParent));
	return 0;
}

const unsigned int	ChannelManager::MoveChannel(const std::string& patternChannel, IChannel* parent)
{
	this->GetChannel(patternChannel)->SetParent(parent);
	return 0;
}

const unsigned int	ChannelManager::MoveChannel(const std::string& patternChannel, const unsigned int idParent)
{
	this->GetChannel(patternChannel)->SetParent(this->GetChannel(idParent));
	return 0;
}

const unsigned int	ChannelManager::MoveChannel(const std::string& patternChannel, const std::string& patternParent)
{
	this->GetChannel(patternChannel)->SetParent(this->GetChannel(patternParent));
	return 0;
}

IChannel*	ChannelManager::GetChannel(const unsigned int id)
{
	std::list<IChannel*>::iterator	iteCurrent = this->_channel.begin();
	std::list<IChannel*>::iterator	iteEnd = this->_channel.end();
	while (iteCurrent != iteEnd)
	{
		if ((*iteCurrent)->GetId() == id)
			return *iteCurrent;
		++iteCurrent;
	}
	return NULL;
}

IChannel*	ChannelManager::GetChannel(const std::string& pattern)
{
	std::list<IChannel*>::iterator	iteCurrent = this->_channel.begin();
	std::list<IChannel*>::iterator	iteEnd = this->_channel.end();
	while (iteCurrent != iteEnd)
	{
		if ((*iteCurrent)->GetName() == pattern)
			return *iteCurrent;
		++iteCurrent;
	}
	return NULL;
}

// WARNING : on revoit la copie en reference ou en pointeur ?
std::list<IChannel*>&	ChannelManager::GetChannelList()
{
	std::list<IChannel*>* lst = new std::list<IChannel*>();
	*lst = this->_channel;
	return *lst;
}

bool	ChannelManager::ChannelExists(const unsigned int idParent, const std::string& name)
{
	IDatabase::DbResult*	result = Configuration::GetConfiguration()->GetDatabase()->SelectChannel(idParent, name);

	if (result->size())
		return true;
	return false;
}